package carassius.DAL;

import carassius.BLL.Events.Animal.AnimalPropertyChangedEvent;
import carassius.BLL.Events.Animal.AnimalPropertyChangedEvent.AnimalProperty;
import carassius.BLL.Events.Animal.AnimalPropertyChangedEventListener;
import carassius.BLL.Events.Animal.AnimalPropertyChangedEventPublisher;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;

/**
 *
 * @author siebz0r
 */
public class AnimalRow
		extends OrganismRow
		implements AnimalPropertyChangedEventPublisher
{
	//<editor-fold defaultstate="collapsed" desc="Fields">
	private String _feed, _breed, _origin;
	private Integer _aquariumLength, _aquariumHeight, _aquariumLiter;
	private boolean _schooling;
	private final Object FEED_LOCK,
			BREED_LOCK,
			ORIGIN_LOCK,
			AQUARIUM_LENGTH_LOCK,
			AQUARIUM_HEIGTH_LOCK,
			AQUARIUM_LITER_LOCK,
			SCHOOLING_LOCK;
	private final ArrayList<AnimalPropertyChangedEventListener> _animalPropertyChangedEventListeners;
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Constructors">
	public AnimalRow(ResultSet resultSet) throws SQLException
	{
		super(resultSet);
		_feed = resultSet.getString("feed");
		_aquariumLength = resultSet.getInt("aquarium_length");
		_aquariumHeight = resultSet.getInt("aquarium_height");
		_aquariumLiter = resultSet.getInt("aquarium_liter");
		_breed = resultSet.getString("breed");
		_origin = resultSet.getString("origin");
		_schooling = resultSet.getBoolean("schooling");
		_animalPropertyChangedEventListeners = new ArrayList<AnimalPropertyChangedEventListener>();
		FEED_LOCK = new Object();
		BREED_LOCK = new Object();
		ORIGIN_LOCK = new Object();
		AQUARIUM_LENGTH_LOCK = new Object();
		AQUARIUM_HEIGTH_LOCK = new Object();
		AQUARIUM_LITER_LOCK = new Object();
		SCHOOLING_LOCK = new Object();
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Public Properties">
	public Integer getAquariumHeight()
	{
		synchronized (AQUARIUM_HEIGTH_LOCK)
		{
			return _aquariumHeight;
		}
	}

	public boolean setAquariumHeight(Integer aquariumHeight)
	{
		boolean result = false;
		synchronized (AQUARIUM_HEIGTH_LOCK)
		{
			if (aquariumHeight != _aquariumHeight)
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE animal SET aquarium_height = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						st.setObject(1, aquariumHeight, Types.INTEGER);
						st.setInt(2, getId());

						if (st.executeUpdate() == 1)
						{
							fireAnimalPropertyChangedEvent(AnimalProperty.AquariumHeight, _aquariumHeight, aquariumHeight);
							_aquariumHeight = aquariumHeight;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_aquariumHeight = aquariumHeight;
				}
			}
		}
		return result;
	}

	public Integer getAquariumLength()
	{
		synchronized (AQUARIUM_LENGTH_LOCK)
		{
			return _aquariumLength;
		}
	}

	public boolean setAquariumLength(Integer aquariumLength)
	{
		boolean result = false;
		synchronized (AQUARIUM_LENGTH_LOCK)
		{
			if (aquariumLength != _aquariumLength)
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE animal SET aquarium_length = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						st.setObject(1, aquariumLength, Types.INTEGER);
						st.setInt(2, getId());

						if (st.executeUpdate() == 1)
						{
							fireAnimalPropertyChangedEvent(AnimalProperty.AquariumLength, _aquariumLength, aquariumLength);
							_aquariumLength = aquariumLength;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_aquariumLength = aquariumLength;
				}
			}
		}
		return result;
	}

	public Integer getAquariumLiter()
	{
		synchronized (AQUARIUM_LITER_LOCK)
		{
			return _aquariumLiter;
		}
	}

	public boolean setAquariumLiter(Integer aquariumLiter)
	{
		boolean result = false;
		synchronized (AQUARIUM_LITER_LOCK)
		{
			if (aquariumLiter != _aquariumLiter)
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE animal SET aquarium_liter = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						st.setObject(1, aquariumLiter, Types.INTEGER);
						st.setInt(2, getId());

						if (st.executeUpdate() == 1)
						{
							fireAnimalPropertyChangedEvent(AnimalProperty.AquariumLiter, _aquariumLiter, aquariumLiter);
							_aquariumLiter = aquariumLiter;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_aquariumLiter = aquariumLiter;
				}
			}
		}
		return result;
	}

	public String getBreed()
	{
		synchronized (BREED_LOCK)
		{
			return _breed;
		}
	}

	public boolean setBreed(String breed)
	{
		boolean result = false;
		synchronized (BREED_LOCK)
		{
			if (breed == null ? _breed != null : !breed.equals(_breed))
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE animal SET breed = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						if (breed != null)
						{
							st.setString(1, breed);
						}
						else
						{
							st.setNull(1, java.sql.Types.VARCHAR);
						}
						st.setInt(2, getId());

						if (st.executeUpdate() == 1)
						{
							fireAnimalPropertyChangedEvent(AnimalProperty.Breed, _breed, breed);
							_breed = breed;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_breed = breed;
				}
			}
		}
		return result;
	}

	public String getFeed()
	{
		synchronized (FEED_LOCK)
		{
			return _feed;
		}
	}

	public boolean setFeed(String feed)
	{
		boolean result = false;
		synchronized (FEED_LOCK)
		{
			if (feed == null ? _feed != null : !feed.equals(_feed))
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE animal SET feed = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						if (feed != null)
						{
							st.setString(1, feed);
						}
						else
						{
							st.setNull(1, java.sql.Types.VARCHAR);
						}
						st.setInt(2, getId());

						if (st.executeUpdate() == 1)
						{
							fireAnimalPropertyChangedEvent(AnimalProperty.Feed, _feed, feed);
							_feed = feed;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_feed = feed;
				}
			}
		}
		return result;
	}

	public String getOrigin()
	{
		synchronized (ORIGIN_LOCK)
		{
			return _origin;
		}
	}

	public boolean setOrigin(String origin)
	{
		boolean result = false;
		synchronized (ORIGIN_LOCK)
		{
			if (origin == null ? _origin != null : !origin.equals(_origin))
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE animal SET origin = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						if (origin != null)
						{
							st.setString(1, origin);
						}
						else
						{
							st.setNull(1, java.sql.Types.VARCHAR);
						}
						st.setInt(2, getId());

						if (st.executeUpdate() == 1)
						{
							fireAnimalPropertyChangedEvent(AnimalProperty.Origin, _origin, origin);
							_origin = origin;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_origin = origin;
				}
			}
		}
		return result;
	}

	public boolean isSchooling()
	{
		synchronized (SCHOOLING_LOCK)
		{
			return _schooling;
		}
	}

	public boolean setSchooling(boolean schooling)
	{
		boolean result = false;
		synchronized (SCHOOLING_LOCK)
		{
			if (getId() >= 0 && schooling != _schooling)
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE animal SET schooling = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						st.setBoolean(1, schooling);
						st.setInt(2, getId());

						if (st.executeUpdate() == 1)
						{
							fireAnimalPropertyChangedEvent(AnimalProperty.Schooling, _schooling, schooling);
							_schooling = schooling;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_schooling = schooling;
				}
			}
		}
		return result;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Public Methods">
	@Override
	public boolean equals(Object obj)
	{
		if (!super.equals(obj))
		{
			return false;
		}
		if (obj == null)
		{
			return false;
		}
		if (getClass() != obj.getClass())
		{
			return false;
		}
		final AnimalRow other = (AnimalRow) obj;
		if ((this._feed == null) ? (other._feed != null) : !this._feed.equals(other._feed))
		{
			return false;
		}
		if ((this._breed == null) ? (other._breed != null) : !this._breed.equals(other._breed))
		{
			return false;
		}
		if ((this._origin == null) ? (other._origin != null) : !this._origin.equals(other._origin))
		{
			return false;
		}
		if (this._aquariumLength != other._aquariumLength)
		{
			return false;
		}
		if (this._aquariumHeight != other._aquariumHeight)
		{
			return false;
		}
		if (this._aquariumLiter != other._aquariumLiter)
		{
			return false;
		}
		if (this._schooling != other._schooling)
		{
			return false;
		}
		return true;
	}

	@Override
	public int hashCode()
	{
		int hash = 7;
		return hash;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Events">
	//<editor-fold defaultstate="collapsed" desc="Animal Property Changed">
	@Override
	public void addAnimalPropertyChangedEventListener(
			AnimalPropertyChangedEventListener listener)
	{
		synchronized (_animalPropertyChangedEventListeners)
		{
			_animalPropertyChangedEventListeners.add(listener);
		}
	}

	@Override
	public void removeAnimalPropertyChangedEventListener(
			AnimalPropertyChangedEventListener listener)
	{
		synchronized (_animalPropertyChangedEventListeners)
		{
			_animalPropertyChangedEventListeners.remove(listener);
		}
	}

	private void fireAnimalPropertyChangedEvent(AnimalProperty property,
												Object oldVal, Object newVal)
	{
		final AnimalPropertyChangedEvent evt = new AnimalPropertyChangedEvent(this, property, oldVal, newVal);
		synchronized (_animalPropertyChangedEventListeners)
		{
			for (AnimalPropertyChangedEventListener listener : _animalPropertyChangedEventListeners)
			{
				listener.animalPropertyChanged(evt);
			}
		}
	}
	//</editor-fold>
	//</editor-fold>
}
